#include "WavesApp.h"



WavesApp::WavesApp():
	mDevice(0),mTheta(0)
{
	D3DXMatrixIdentity(&mLandWorld);
	D3DXMatrixIdentity(&mWavesWorld);
	D3DXMatrixIdentity(&mView);
	D3DXMatrixIdentity(&mProj);
	D3DXMatrixIdentity(&mWVP);
}


WavesApp::~WavesApp()
{
	if (mDevice)
		mDevice->ClearState();

	ReleaseCOM(mFX);
	ReleaseCOM(mVertexLayout);
	ReleaseCOM(mWireframeRS);
}

void WavesApp::initApp(ID3D10Device * device)
{
	mDevice = device;
	m_peakVallys.init(device, 129, 129, 1.0f);
	m_Waves.init(device, 257, 257, 0.5f, 0.03f, 3.25f, 0.4f);
	buildRenderStates();
	buildFX();
	buildVertexLayouts();
}

void WavesApp::onResize(int mClientWidth, int mClientHeight)
{
	float aspect = (float)mClientWidth / mClientHeight;
	D3DXMatrixPerspectiveFovLH(&mProj, 0.25f*PI, aspect, 1.0f, 1000.0f);
}

void WavesApp::updateScene(float deltatime, float gametime)
{

	static float t_base = 0.0f;
	if ((gametime - t_base) >= 0.25f)
	{
		t_base += 0.25f;

		DWORD i = 5 + rand() % 250;
		DWORD j = 5 + rand() % 250;

		float r = RandF(1.0f, 2.0f);

		m_Waves.disturb(i, j, r);
	}

	// Update angles based on input to orbit camera around scene.
	if (GetAsyncKeyState('A') & 0x8000)
		mTheta -= 2.0f*deltatime;
	if (GetAsyncKeyState('D') & 0x8000)	
		mTheta += 2.0f*deltatime;
	if (GetAsyncKeyState('W') & 0x8000)	mPhi -= 2.0f*deltatime;
	if (GetAsyncKeyState('S') & 0x8000)	mPhi += 2.0f*deltatime;
	if (GetAsyncKeyState('Z') & 0x8000)	mRadius -= 25.0f*deltatime;
	if (GetAsyncKeyState('X') & 0x8000)	mRadius += 25.0f*deltatime;

	// Restrict the angle mPhi and radius mRadius.
	if (mPhi < 0.1f)	mPhi = 0.1f;
	if (mPhi > PI - 0.1f)	mPhi = PI - 0.1f;

	if (mRadius < 25.0f) mRadius = 25.0f;


	// Convert Spherical to Cartesian coordinates: mPhi measured from +y
	// and mTheta measured counterclockwise from -z.
	float x = mRadius*sinf(mPhi)*sinf(mTheta);
	float z = -mRadius*sinf(mPhi)*cosf(mTheta);
	float y = mRadius*cosf(mPhi);

	// Build the view matrix.
	D3DXVECTOR3 pos(x, y, z);
	D3DXVECTOR3 target(0.0f, 0.0f, 0.0f);
	D3DXVECTOR3 up(0.0f, 1.0f, 0.0f);
	D3DXMatrixLookAtLH(&mView, &pos, &target, &up);

	m_Waves.update(deltatime);
}

void WavesApp::Draw()
{
	mDevice->OMSetDepthStencilState(0, 0);
	float blendFactors[] = { 0.0f, 0.0f, 0.0f, 0.0f };
	mDevice->OMSetBlendState(0, blendFactors, 0xffffffff);
	mDevice->IASetInputLayout(mVertexLayout);
	mDevice->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

	D3D10_TECHNIQUE_DESC techDesc;
	mTech->GetDesc(&techDesc);

	for (UINT i = 0; i < techDesc.Passes; ++i)
	{
		ID3D10EffectPass* pass = mTech->GetPassByIndex(i);

		mWVP = mLandWorld*mView*mProj;
		mfxWVPVar->SetMatrix((float*)&mWVP);
		pass->Apply(0);
		m_peakVallys.draw();

		mDevice->RSSetState(mWireframeRS);
		mWVP = mWavesWorld*mView*mProj;
		mfxWVPVar->SetMatrix((float*)&mWVP);
		pass->Apply(0);
		m_Waves.draw();
	}
}

void WavesApp::buildRenderStates()
{

	D3D10_RASTERIZER_DESC rsDesc;
	ZeroMemory(&rsDesc, sizeof(D3D10_RASTERIZER_DESC));
	rsDesc.FillMode = D3D10_FILL_WIREFRAME;
	rsDesc.CullMode = D3D10_CULL_BACK;
	mDevice->CreateRasterizerState(&rsDesc, &mWireframeRS);
}

void WavesApp::buildFX()
{
	DWORD shaderFlags = D3D10_SHADER_ENABLE_STRICTNESS;
#if defined( DEBUG ) || defined( _DEBUG )
	shaderFlags |= D3D10_SHADER_DEBUG;
	shaderFlags |= D3D10_SHADER_SKIP_OPTIMIZATION;
#endif
	string currentPath = MyMethods::GetCurrentPath();

	string fxPath = currentPath + "\\..\\fxes\\color.fx";
	ID3D10Blob* compilationErrors = 0;
	HRESULT hr = 0;
	hr = D3DX10CreateEffectFromFile(MyMethods::stringToLPCWSTR(fxPath), 0, 0,
		"fx_4_0", shaderFlags, 0, mDevice, 0, 0, &mFX, &compilationErrors, 0);


	mTech = mFX->GetTechniqueByName("ColorTech");

	mfxWVPVar = mFX->GetVariableByName("gWVP")->AsMatrix();
}

void WavesApp::buildVertexLayouts()
{
	// Create the vertex input layout.
	D3D10_INPUT_ELEMENT_DESC vertexDesc[] =
	{
		{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 },
		{ "COLOR",    0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D10_INPUT_PER_VERTEX_DATA, 0 }
	};

	// Create the input layout
	D3D10_PASS_DESC PassDesc;
	mTech->GetPassByIndex(0)->GetDesc(&PassDesc);
	mDevice->CreateInputLayout(vertexDesc, 2, PassDesc.pIAInputSignature,
		PassDesc.IAInputSignatureSize, &mVertexLayout);
}
